<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Controller;

use Hyperf\Cache\Listener\DeleteListenerEvent;
use Hyperf\Collection\Collection;
use Hyperf\Contract\SessionInterface;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Cache\Annotation\Cacheable;
use Hyperf\Config\Annotation\Value;
use Hyperf\Contract\ConfigInterface;
use League\Flysystem\FilesystemException;
use Psr\EventDispatcher\EventDispatcherInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Coroutine\Coroutine;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Log\LoggerInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Paginator\Paginator;
use Hyperf\View\RenderInterface;
use function Hyperf\Coroutine\parallel;
use function Hyperf\ViewEngine\view;


/**
 * IndexController
 * Class IndexController
 * @package App\Controller
 * @author ^2_3^王尔贝
 */
#[Controller]
class IndexController extends AbstractController
{
    /**
     * 事件调度器
     * @var EventDispatcherInterface
     */
    #[Inject]
    protected EventDispatcherInterface $dispatcher;

    /**
     * 配置对象
     * 依赖注入配置对象
     * @var ConfigInterface
     */
    #[Inject]
    private ConfigInterface $config;

    /**
     * 日志
     * 构造函数依赖注入
     * @var |null
     */
    private LoggerInterface $logger;

    /**
     * session会话接口
     * @var SessionInterface
     */
    #[Inject]
    private SessionInterface $session;

    /**
     * 数据库驱动配置项
     * @var
     */
    #[Value('databases.default.driver')]
    private $databaseDefaultDriver;

    /**
     * 构造函数
     * IndexController constructor.
     * @param LoggerFactory $loggerFactory
     */
    public function __construct(LoggerFactory $loggerFactory)
    {
        // 第一个参数对应日志的 name, 第二个参数对应 config/autoload/logger.php 内的 key
        // 'log_^2_3^_debug' => 日志信道Channel名称
        $this->logger = $loggerFactory->get('log_^2_3^_debug', 'default');
    }

    /**
     * Blade布局继承
     * @description: Blade布局继承示例，渲染模板
     * @return {*}
     */
    #[RequestMapping(path: "layout_extend", methods: "get")]
    public function layoutExtend()
    {
        //// 模版使用组件
        // <x-alert type="alert组件，type属性值" :message=$message />
        return view('child', ['message' => 'message属性值']);
    }
    
    /**
     * 视图渲染
     * @description: 视图渲染功能测试
     * @param {RenderInterface} $render
     * @param {RequestInterface} $request
     * @param {ResponseInterface} $response
     * @return {*}
     */
    #[RequestMapping(path: "view_hello", methods: "get")]
    public function viewHello(RenderInterface $render, RequestInterface $request, ResponseInterface $response)
    {
        $params = $request->all();
        $name = $request->input('name') ?? 'Hyperf';
        
        $data = [
            'name' => $name, 
            'message' => "alert组件message属性值",
            'array' => ['python3', 'php']
        ];
        return $render->render('hello', $data);
    }

    /**
     * 文件系统
     * @param \League\Flysystem\Filesystem $filesystem
     * @param ResponseInterface $response
     * @return \Psr\Http\Message\ResponseInterface
     * @author ^2_3^王尔贝
     */
    #[RequestMapping(path: "file_system_demo", methods: "get,post")]
    public function filesystemDemo(\League\Flysystem\Filesystem $filesystem, ResponseInterface $response)
    {
        $result = [
            'developer_name' => '^2_3^'
        ];

        //// Process Upload
        // config/autoload/file.php 指定存储的根目录
//        $file = $this->request->file('upload');
//        $stream = fopen($file->getRealPath(), 'r+');
//        $filesystem->writeStream('upload/'.$file->getClientFilename(), $stream);
//        fclose($stream);

        //// Write Files
//        $filesystem->write('upload/text.txt', 'contents ^2_3^');

        //// Add local file
//        $streamObj = fopen(BASE_PATH.'/runtime/upload/text.txt', 'r+');
//        $filesystem->writeStream('upload/text_new.txt', $streamObj);
//        if (is_resource($streamObj)) {
//            fclose($streamObj);
//        }

        //// Check if a file exists
//        $isExist = $filesystem->has('upload/text_new.txt'); //此时路径相对文件驱动配置中的根目录;
//        $isExist = $filesystem->fileExists('upload/text_new.txt');

        //// Read Files
//        $contents = $filesystem->read('upload/text_new.txt');

        //// Delete Files
//        $filesystem->delete('upload/text_new.txt');

        //// Rename Files
//        $filesystem->move('upload/text.txt', 'upload/text_move.txt');

        //// Copy Files
//        $filesystem->copy('upload/text_move.txt', 'upload/text_copy.txt');

        //// Listing directory contents
        try {
            $listContents = $filesystem->listContents('/', true);
            $contentsArr = [];

            /** @var \League\Flysystem\StorageAttributes $item */
            foreach ($listContents as $item) {
                $str = '';

                $path = $item->path();
                $str = "路径: {$path}";

                if ($item instanceof \League\Flysystem\FileAttributes) {
                    // handle the file
                    $str .= "; 文件类型";

                } elseif ($item instanceof \League\Flysystem\DirectoryAttributes) {
                    // handle the directory
                    $str .= "; 目录类型";
                }

                $contentsArr[] = $str;
            }
            $result['contents_arr'] = $contentsArr;

        } catch (FilesystemException $exception) {
            // handle the error
        }

        return $response->json($result);
    }

    /**
     * session会话示例
     * @return array
     * @author ^2_3^王尔贝
     */
    #[RequestMapping(path: "session_demo", methods: "get")]
    public function sessionDemo()
    {
        $this->session->set('developer_name', '^2_3^ cyb');
        $developerName = $this->session->get('developer_name');

        return [
            'developer_name' => $developerName
        ];
    }

    /**
     * 分页器
     * @param RequestInterface $request
     * @return Paginator
     * @author ^2_3^王尔贝
     */
    #[RequestMapping(path: "paginator_demo", methods: "get")]
    public function paginatorDemo(RequestInterface $request)
    {
        $currentPage = (int)$request->input('page', 1);
        $perPage = (int)$request->input('per_page', 2);

        // 这里根据 $currentPage 和 $perPage 进行数据查询，以下使用 Collection 代替
        $collection = new Collection([
            ['id' => 1, 'name' => 'Tom'],
            ['id' => 2, 'name' => 'Sam'],
            ['id' => 3, 'name' => 'Tim'],
            ['id' => 4, 'name' => 'Joe'],
        ]);
        $users = array_values($collection->forPage($currentPage, $perPage)->toArray());

        return new Paginator($users, $perPage, $currentPage);
    }

    /**
     * 清除缓存
     * @param int $id
     * @return array
     * @author ^2_3^王尔贝
     */
    #[RequestMapping(path: "cache_demo_flush/{id:\d+}", methods: "post")]
    public function cacheDemoFlush($id = 0)
    {
        //// 清除缓存 cacheDemo()方法设置的缓存
        $result = $this->dispatcher->dispatch(new DeleteListenerEvent('info-cache-update', [$id]));
        return ['result' => $result];
    }

    /**
     * 缓存示例
     * @param int $id
     * @return array
     * @author ^2_3^王尔贝
     */
    #[RequestMapping(path: "cache_demo/{id:\d+}", methods: "get")]
    #[Cacheable(prefix: "info", ttl: 9000, listener: "info-cache-update")]
    public function cacheDemo($id = 0)
    {
        $this->logger->info('cacheDemo > ^2_3^');
        return ['path' => 'cache_demo', 'methods' => ['get'], 'id' => $id];
    }

    /**
     * 分块传输编码 Chunk
     * https://hyperf.wiki/3.1/#/zh-cn/response
     * @param ResponseInterface $response
     * @return string
     * @author ^2_3^王尔贝
     */
    #[RequestMapping(path: "transfer_chunk", methods: "get")]
    public function transferChunk(ResponseInterface $response)
    {
        for ($i=1; $i<=10; $i++) {
            sleep(1);
            $dateTime = date('Y-m-d H:i:s');
            $response->write("[{$dateTime}] 第{$i}次传输！\n");
        }

        return 'end'; //'end'字符串不会正常返回;
    }

    /**
     * @param RequestInterface $request
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @author ^2_3^王尔贝
     */
    #[RequestMapping(path: "auto_route", methods: "get,post")]
    public function autoRoute(RequestInterface $request)
    {
        //// redis配置数据 (config/autoload/redis.php)
        $redisConfigArr = $this->config->get('redis');
        $this->logger->info('autoRoute > ^2_3^', ['redis_config_arr' => $redisConfigArr]);

        //// 简单缓存
        $simpleCache = $this->container->get(\Psr\SimpleCache\CacheInterface::class);
        $simpleCache->set('developer', 'cyb');
        $developer = $simpleCache->get('developer');

        $params = $request->all();
        return ['params' => $params, 'redis_config_arr' => $redisConfigArr, 'key -> developer' => $developer];
    }

    /**
     * index
     * 路由定义文件 config/routes.php
     * @return array
     * @author ^2_3^王尔贝
     */
    public function index()
    {
        $user = $this->request->input('user', 'Hyperf');
        $method = $this->request->getMethod();

        ///1/ 协程
        // 传递的数组参数您也可以带上 key 便于区分子协程，返回的结果也会根据 key 返回对应的结果
        $result_start = date('Y-m-d H:i:s');
        $result = parallel([
            'parallel > fn1' => function () {
                sleep(3);
                return Coroutine::id();
            },
            'parallel > fn2' => function () {
                sleep(2);
                return Coroutine::id();
            }
        ]);
        $result_end = date('Y-m-d H:i:s');
        $result = array_merge($result, ['result_start' => $result_start, 'result_end' => $result_end]);

        return [
            'method' => $method,
            'message' => "^2_3^ Hello {$user}.",
            'co_result' => $result,
            'database_default_driver' => $this->databaseDefaultDriver,
        ];
    }
}
